﻿using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace MediaImporter.Controllers
{
    class BackgroundCopyController
    {       
        class WorkerArgs
        {
            public bool Overwrite { get; set; }
            public NameValueCollection ToCopy { get; set; }
        }

        public event RunWorkerCompletedEventHandler Done;
        public event EventHandler<FileCopiedEventArgs> FileCopied;

        BackgroundWorker worker = new BackgroundWorker();
        Controls.ProgressControl progressControl;

        public BackgroundCopyController(Controls.ProgressControl progressControl)
        {
            worker.WorkerReportsProgress = true;
            worker.WorkerSupportsCancellation = true;
            worker.DoWork += worker_DoWork;
            worker.ProgressChanged += worker_ProgressChanged;
            worker.RunWorkerCompleted += worker_RunWorkerCompleted;
            this.progressControl = progressControl; 
            progressControl.AbortPressed += progressControl1_AbortPressed;
        }

        public void StartCopyFiles(string targetDir, IEnumerable<string> filesToCopy, string description)
        {
            IList<string> processFiles = filesToCopy.ToList();
            bool overwrite = false;
            if (!Directory.Exists(targetDir))
                Directory.CreateDirectory(targetDir);
            else
            {
                string[] exisingFiles = Directory.GetFiles(targetDir, "*.*").Select(file => Path.GetFileName(file)).ToArray();

                List<string> toCopyNames = new List<string>();
                foreach (string file in filesToCopy)
                    toCopyNames.Add(Path.GetFileName(file));
                int existingCount = exisingFiles.Count(existing => toCopyNames.Any(toCopy => string.Compare(existing, toCopy, true) == 0));
                if (existingCount > 0)
                {
                    var result = MessageBox.Show(string.Format("{0} of {1} files already exists in '{2}'. Overwrite existing files?", existingCount, filesToCopy.Count(), targetDir), "Copy files", MessageBoxButtons.YesNoCancel);
                    if (result == System.Windows.Forms.DialogResult.Cancel)
                    {
                        if (Done != null)
                            Done(this, new RunWorkerCompletedEventArgs(null,null,true));
                        return;
                    }

                    if (result == System.Windows.Forms.DialogResult.No)
                    {
                        var onlyNewFiles = new List<string>();
                        foreach (string fileToCopy in filesToCopy)
                        {
                            string name = Path.GetFileName(fileToCopy);
                            if (!exisingFiles.Any(file => string.Compare(name, file, true) == 0))
                            {
                                onlyNewFiles.Add(fileToCopy);
                            }
                        }
                        processFiles = onlyNewFiles;
                    }

                    overwrite = result == System.Windows.Forms.DialogResult.Yes;
                }
            }
            progressControl.Show(processFiles.Count, description);
            CopyFilesAsync(processFiles, targetDir, overwrite);
        }

        private void CopyFilesAsync(IList<string> files, string destination, bool overwrite)
        {
            NameValueCollection toCopy = new NameValueCollection();
            foreach (string file in files)
            {
                toCopy[file] = Path.Combine(destination, Path.GetFileName(file));
            }
            worker.RunWorkerAsync(new WorkerArgs() { ToCopy = toCopy, Overwrite = overwrite });
        }

        void worker_DoWork(object sender, DoWorkEventArgs e)
        {
            int progress = 0;
            WorkerArgs args = (WorkerArgs)e.Argument;
            NameValueCollection toCopy = (NameValueCollection)args.ToCopy;
            foreach (string source in toCopy.Keys)
            {
                if (worker.CancellationPending)
                {
                    e.Cancel = true;
                    return;
                }

                File.Copy(source, toCopy[source], args.Overwrite);
                progress++;
                worker.ReportProgress(progress, source);
            }
        }

        void progressControl1_AbortPressed(object sender, EventArgs e)
        {
            if (worker.IsBusy)
                worker.CancelAsync();
        }

        void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            progressControl.Hide();
            if (e.Error != null)
            {
                MessageBox.Show(e.Error.ToString());
            }
            else
            {
                if (e.Cancelled)
                    MessageBox.Show("Aborted");
            }
            if (Done != null)
                Done(this, e);
        }

        void worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {

            progressControl.SetProgress(e.ProgressPercentage);
            if (FileCopied != null)
                FileCopied(this, new FileCopiedEventArgs { Name = e.UserState as string });
        }
    }
}
